#include "clientwindow.h"
#include "ui_clientwindow.h"
#include "taskqueue.h"
#include "clientsubthread.h"

#include <QDateTime>

ClientWindow::ClientWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::ClientWindow)
{
    ui->setupUi(this);

    // 按钮组的初始化
    m_btnGrp.addButton(ui->consultBtn, 0);
    m_btnGrp.addButton(ui->verifyBtn, 1);
    m_btnGrp.addButton(ui->logoutBtn, 2);
    m_btnGrp.addButton(ui->setBtn, 3);

    // 设置按钮属性, 添加可选中属性(按下不会弹起)
    QList<QAbstractButton *> btnList = m_btnGrp.buttons();
    for(int i=0; i<btnList.size(); ++i)
    {
        // m_btnGrp.button(i)->setCheckable(true);
        btnList.at(i)->setCheckable(true);
    }
    // 设置第一个按钮密钥协商默认是被选中的
    ui->consultBtn->setChecked(true);
    m_prevBtn = ui->consultBtn;
    m_index = 0;

    // 按钮组中的按钮点击事件, 处理按钮的显示状态
    void (QButtonGroup::*clicked)(int) = &QButtonGroup::buttonClicked;
    connect(&m_btnGrp, clicked, this, [=](int index)
    {
        m_index = index;    // 更新当前功能对应的编号
        if(m_btnGrp.button(index) == ui->setBtn)
        {
            // 切换到设置窗口
            ui->stackedWidget->setCurrentWidget(ui->set);
            // 切换到设置窗口的客户端设置窗口
            ui->set->showPage(ConfigSet::Client);
        }
        else
        {
            // 切换的任务窗口
            ui->stackedWidget->setCurrentWidget(ui->task);
            ui->stackedTask->setCurrentIndex(0);
            // 切换任务按钮上显示的标题信息
            QStringList titles;
            titles << "开始秘钥协商" << "开始秘钥校验" << "开始秘钥注销";
            ui->startTask->setText(titles[index]);
        }
        // 按钮状态切换, 按下新的按钮的时候, 就的按钮变成未选中状态
        m_prevBtn->setChecked(false);   // 之前按下的按钮弹起
        // 当前按下的按钮设置为选中状态, index 对应的按钮
        m_btnGrp.button(index)->setChecked(true);
        // 保存当前被按下的按钮的地址
        m_prevBtn = m_btnGrp.button(index);
    });

    // 实例化客户端操作类对象
    m_cliOP = new ClientOperation;
    connect(m_cliOP, &ClientOperation::sendMsg, this, [=](QString msg)
    {
        QDateTime tm = QDateTime::currentDateTime();
        QString curTm = tm.toString("yyyy-MM-dd hh:mm:ss");
        // 显示msg到窗口中即可
        ui->taskMsg->append(curTm + ": " + msg);
    });
}

ClientWindow::~ClientWindow()
{
    delete ui;
}

/*
 * 秘钥协商, 校验, 注销 功能函数是在当前类中实现, 还是在其他类中实现呢?
 *  - 当前类: 没问题 (界面操作和业务逻辑在一起)
 *  - 其他类: 也没有问题 (界面操作和逻辑处理是分离的) --> 项目中选择这种方式
*/
// 添加秘钥协商, 秘钥校验, 秘钥注销任务到任务队列中
void ClientWindow::on_startTask_clicked()
{
    QVector<Qt::GlobalColor> colors;
    colors << Qt::red << Qt::green << Qt::blue << Qt::gray << Qt::cyan
           << Qt::black << Qt::darkGray << Qt::darkBlue << Qt::darkRed
           << Qt::darkYellow << Qt::darkCyan << Qt::darkGreen;
    Qt::GlobalColor color = colors[rand() % colors.size()];
    ui->taskMsg->setTextColor(color);

    // 显示日志窗口
    ui->stackedTask->setCurrentIndex(1);

    ArgInfo* args = new ArgInfo;    // 任务函数的参数对象
    // 一个按钮对应三种请求, 当前是哪一种请求, 需要进行判断
    // 如果判断的条件比较多, 建议使用switch, 效率比 if ... else if ... else if .. else 高
    args->object = m_cliOP;
    switch(m_index)
    {
    case 0:
        // 初始化要添加的任务, 初始化对象 t
        // 秘钥协商
        args->prepare = ClientOperation::consultPrepare;
        args->dispose = ClientOperation::consultDispose;
        break;
    case 1:
        // 秘钥校验
        args->prepare = ClientOperation::verifyPrepare;
        args->dispose = ClientOperation::verifyDispose;
        break;
    case 2:
        // 秘钥注销
        args->prepare = ClientOperation::logoutPrepare;
        args->dispose = ClientOperation::logoutDispose;
        break;
    default:
        break;
    }

    // 将初始化的任务添加到任务队列中
    TaskQueue* taskQ = TaskQueue::getInstance();
    // 生产者(主线程)添加任务
    taskQ->addTask(ClientOperation::communication, args);
}

void ClientWindow::on_backTask_clicked()
{
    // 切换到执行任务的窗口
    ui->stackedTask->setCurrentIndex(0);
}

void ClientWindow::closeEvent(QCloseEvent *event)
{
    // 当用户关闭窗口的时候, 添加任务, 让子线程开始工作
    TaskQueue::getInstance()->addTask(ClientOperation::lastTask, NULL);
}
